#ifndef _HASHTABLELTS_H
#define _HASHTABLELTS_H

#include <stdio.h>
#include <stdlib.h>
#include "SyntacticTreeLibrary.h"

#define HASHTABLE_SIZE 100000
#define MAX_LTSNODE_ID_LENGHT 1000
#define MAX_RULE_LENGHT 20

typedef struct {
	char rule[MAX_RULE_LENGHT];//Although I checked that the maximum rule needs only 14 characters A-RaceParCoop
	char subState[MAX_LTSNODE_ID_LENGHT];
} transitionLTS;

typedef struct {
	int state;
	char id[MAX_LTSNODE_ID_LENGHT];
	Node *node;

	int numberOfTransitions;
	transitionLTS subStates[20];

} stateLTS;

typedef struct {
	stateLTS *LTS;
} hashTableLTS;

hashTableLTS* hLTS_create() {
	hashTableLTS *hashTable = (hashTableLTS *) malloc(sizeof(hashTableLTS));
	hashTable->LTS = (stateLTS *) malloc(sizeof(stateLTS) * HASHTABLE_SIZE);

	int i;
	for (i = 0; i < HASHTABLE_SIZE; i++) {
//		hashTable->LTS[i].id = (char *)malloc(sizeof(char)*max_id);
		hashTable->LTS[i].state = 0;
//		hashTable->LTS[i].node = (Node *)malloc(sizeof(Node));
		//Firstly, it only gets memory for one transition but it could store more, which would force to get a wide amount of memory
//		hashTable->LTS[i].subStates = (transitionLTS *)malloc(sizeof(transitionLTS));
	}

	return hashTable;
}

int getKey(char *process) {
	int length = strlen(process);
	int i, j;

	int key = 0;

	for (i = 0; i < length; i++) {
		int ascii = process[i];
		j = i % 10;
		key += (ascii * (j + 1));
	}

	key += length;
	return key;
}

int hashFunction(int key, int index) {

//	int key = getKey(process);

//	float h1f = key / HASHTABLE_SIZE;
	int h1 = key % HASHTABLE_SIZE;
//	float h2f = 1 + (key / (HASHTABLE_SIZE - 1));
	int h2 = 1 + (key % (HASHTABLE_SIZE - 1));
	int h = (h1 + (index * h2)) % HASHTABLE_SIZE;

	return h;
}

int hLTS_insert(hashTableLTS *table, stateLTS *node) {

	int i, h, key; /*It could be wrong*/
	/* | */
	/* | */
	/*\ /*/
	for (i = 0; i < HASHTABLE_SIZE; ++i) {

		key = getKey(node->id);
		h = hashFunction(key, i);

		if (table->LTS[h].state == 0) {
			table->LTS[h] = *node;

//			table->LTS[h].id = node->id;
//			table->LTS[h].node = node->node;
//			table->LTS[h].numberOfTransitions = node->numberOfTransitions;
//			//It is not necessary to store now the transitions, due to this
//			//transitions will be added when the node will be processed
////			int i;
////			for (i = 0; i < table->LTS[h].numberOfTransitions; i++) {
////				table->LTS[h].subStates[i] = node->subStates[i];
////			}
			table->LTS[h].state = 1;
			return h;
		}

		if (i == HASHTABLE_SIZE - 1) {
			printf(
					"Finally, this node has not been inserted in the hash table\n");
		}
	}

	return -1;
}

void hLTS_printHashTableState(hashTableLTS *table) {
	int i, j;
	for (i = 0; i < HASHTABLE_SIZE; ++i) {
		if (table->LTS[i].state != 0) {
			printf("In position %d there is the node %s: : ", i,
					table->LTS[i].id);
			sT_printout(table->LTS[i].node);
			printf("\n");
			if (table->LTS[i].numberOfTransitions == 0) {
				printf("There are 0 LTS transitions\n");
			} else {
				for (j = 0; j < table->LTS[i].numberOfTransitions; j++) {
					printf("| %s ---> %s |", table->LTS[i].subStates[j].rule,
							table->LTS[i].subStates[j].subState);
				}
				printf("\n");
			}
		}

	}
}

stateLTS* hLTS_getNode(hashTableLTS *table, char *nodeId) {
	int i, h, key;
	key = getKey(nodeId);

	stateLTS *resultState = (stateLTS *) malloc(sizeof(stateLTS));

	for (i = 0; i < HASHTABLE_SIZE; ++i) {
		h = hashFunction(key, i);
		if (strcmp(table->LTS[h].id, nodeId) == 0) {
//			resultState->id = table->LTS[h].id;
//			resultState->node = table->LTS[h].node;
//			resultState->state = table->LTS[h].state;
//			resultState->numberOfTransitions =
//					table->LTS[h].numberOfTransitions;
//			int i;
//			for (i = 0; i < resultState->numberOfTransitions; i++) {
//				resultState->subStates[i] = table->LTS[h].subStates[i];
//			}
			//It only sends a pointer to the position in the hash table, in order to
			// be able to modify substates information in the node which is being
			//processed
			resultState = &(table->LTS[h]);

			break;
		}

		if (i == HASHTABLE_SIZE - 1) {
			printf("Finally, this node has not been found in the hash table\n");
		}

	}

	return resultState;
}

int hLTS_getNumberOfNodes(hashTableLTS *table) {
	int i, j;
	j = 0;
	for (i = 0; i < HASHTABLE_SIZE; ++i) {
		if (table->LTS[i].state == 1) {
			j++;
		}
	}
	return j;
}

#endif
